#include "stm32regs.h"
#include "stm32regbit.h"
#include "stm32_gpio.h"
#include "stm32_usart.h"

#define USART_RXFLAG_IDLE 0
#define USART_RXFLAG_BUSY 1
#define USART_RXFLAG_FINISH 2
#define USART_TXFLAG_IDLE 0
#define USART_TXFLAG_BUSY 1
#define USART_DELAYTIME 4
#define USART1_TX_BUFFER_MAX 512
#define USART1_RX_BUFFER_MAX 512
struct
{
  vu8 RXData[USART1_RX_BUFFER_MAX]; //接收缓冲
  vu8 RXWriteCounter;               //接收区数据写入计数器
  vu8 RXReadCounter;                //接收区数据读出计数器
  vu8 RXFinishTime;                 //接收完成计时器,保证收到完整的包，必须放定时器中断
  vu8 RXFlag;                       //接收状态标志，0空闲，1忙碌，2完成

  vu8 TXData[USART1_TX_BUFFER_MAX]; //发送缓冲
  vu8 TXWriteCounter;               //发送区数据计数器
  vu8 TXReadCounter;                //等待发送的数据长度
  vu8 TXFinishTime;                 //发送完成计时器,保证发送完整的包，必须放定时器中断
  vu8 TXFlag;                       //发送状态标志，0空闲，1忙碌
} Usart1Buffer;
#if USART1_RS485_ENABLE
#define USART1_ENABLE_PIN LL_GPIO_PIN_11
#define USART1_ENABLE_PORT GPIOA
#define USART1_SEND_ENABLE LL_GPIO_SetOutputPin(USART1_ENABLE_PORT, USART1_ENABLE_PIN)
#define USART1_RECEIVE_ENABLE LL_GPIO_ResetOutputPin(USART1_ENABLE_PORT, USART1_ENABLE_PIN)
#endif

static const uint32_t USART_PRESCALER_TAB[] =
    {
        1UL,
        2UL,
        4UL,
        6UL,
        8UL,
        10UL,
        12UL,
        16UL,
        32UL,
        64UL,
        128UL,
        256UL};

#define USART_DIV_SAMPLING8(__PERIPHCLK__, __PRESCALER__, __BAUDRATE__) (((((__PERIPHCLK__) / (USART_PRESCALER_TAB[(__PRESCALER__)])) * 2U) + ((__BAUDRATE__) / 2U)) / (__BAUDRATE__))
#define USART_DIV_SAMPLING16(__PERIPHCLK__, __PRESCALER__, __BAUDRATE__) ((((__PERIPHCLK__) / (USART_PRESCALER_TAB[(__PRESCALER__)])) + ((__BAUDRATE__) / 2U)) / (__BAUDRATE__))
#if 1
//#pragma import(__use_no_semihosting)
//标准库需要的支持函数
struct __FILE
{
  int handle;
  /* Whatever you require here. If the only file you are using is */
  /* standard output using printf() for debugging, no file handling */
  /* is required. */
};
/* FILE is typedef’ d in stdio.h. */
FILE __stdout;
//定义_sys_exit()以避免使用半主机模式
void _sys_exit(int x)
{
  x = x;
}
//重定义fputc函数
int fputc(int ch, FILE *f)
{
  while ((USART1->ISR & 0X40) == 0)
    ; //循环发送,直到发送完毕
  USART1->TDR = (u8)ch;
  return ch;
}
#endif

void mygpio_set(GPIO_TypeDef *GPIOx, u32 pin)
{
  u32 pin_pos = 0;
  pin_pos = (1 << pin);
  //设置模式
  /*MODIFY_REG(GPIOA->MODER, (GPIO_MODER_MODE0 << (POSITION_VAL(GPIO_BSRR_BS5) * 2U)),\
						 (GPIO_MODER_MODE0_0 << (POSITION_VAL(GPIO_BSRR_BS5) * 2U))); */
  GPIOx->MODER &= ~(3 << pin * 2U);
  GPIOx->MODER |= (GPIO_MODER_MODE0_1 << (pin * 2U));
  //设置速度
  /*MODIFY_REG(GPIOA->OSPEEDR, (GPIO_OSPEEDR_OSPEED0 << (POSITION_VAL(GPIO_BSRR_BS5) * 2U)),\
						 (GPIO_OSPEEDR_OSPEED0_0 << (POSITION_VAL(GPIO_BSRR_BS5) * 2U)));*/
  GPIOx->OSPEEDR &= ~(3 << pin * 2U);
  GPIOx->OSPEEDR |= (GPIO_OSPEEDR_OSPEED0_1 << pin * 2U);
  //设置上下拉
  /*MODIFY_REG(GPIOA->PUPDR, (GPIO_PUPDR_PUPD0 << (POSITION_VAL(GPIO_BSRR_BS5) * 2U)),\
						 (0 << (POSITION_VAL(GPIO_BSRR_BS5) * 2U)));*/
  GPIOx->PUPDR &= ~(3 << pin * 2U);
  GPIOx->PUPDR |= (0 << pin * 2U);
  //设置输出模式  推挽
  MODIFY_REG(GPIOx->OTYPER, pin_pos, (pin_pos * 0));

  //WRITE_REG(GPIOA->BSRR, GPIO_BSRR_BS5);
}
int mywrite(int ch)
{
  while ((USART1->ISR & 0X40) == 0)
    ; //循环发送,直到发送完毕
  USART1->TDR = (u8)ch;
  return ch;
}

void USART1_Config(u32 pclk2, u32 BaudRate)
{
  uint32_t tmpreg;
  //使能外设时钟
  SET_BIT(RCC->AHB2ENR, RCC_AHB2SMENR_GPIOCSMEN_Msk);
  /* Delay after an RCC peripheral clock enabling */
  tmpreg = READ_BIT(RCC->AHB2ENR, RCC_AHB2SMENR_GPIOCSMEN_Msk);
  (void)tmpreg; //使能PORTC口时钟
  SET_BIT(RCC->APB2ENR, RCC_APB2ENR_USART1EN_Msk);
  /* Delay after an RCC peripheral clock enabling */
  tmpreg = READ_BIT(RCC->APB2ENR, RCC_APB2ENR_USART1EN_Msk);
  (void)tmpreg;

  //串口复位
  RCC->APB2RSTR |= 1 << 14;
  RCC->APB2RSTR &= ~(1 << 14);

  CLEAR_BIT(USART1->CR1, USART_CR1_UE);
#if 0
  __IO uint32_t tmpreg;

#endif
  //使能串口1时钟
  //GPIO_Set(GPIOC, PIN4 | PIN5, GPIO_MODE_OUT, GPIO_OTYPE_PP, GPIO_SPEED_50M, GPIO_PUPD_NONE); //PC4,PC5,复用功能,上拉输出
  mygpio_set(GPIOC, 4);
  mygpio_set(GPIOC, 5);
  GPIO_AF_Set(GPIOC, 4, 7); //PC4,AF7
  GPIO_AF_Set(GPIOC, 5, 7); //PC5,AF7
//使能外设
#if 0
  MODIFY_REG(USARTx->CR1,
              (USART_CR1_M | USART_CR1_PCE | USART_CR1_PS |
              USART_CR1_TE | USART_CR1_RE | USART_CR1_OVER8),
              (USART_InitStruct->DataWidth | USART_InitStruct->Parity |
              USART_InitStruct->TransferDirection | USART_InitStruct->OverSampling));
#endif
#if 1
  MODIFY_REG(USART1->CR1,
             (USART_CR1_M | USART_CR1_PCE | USART_CR1_PS |
              USART_CR1_TE | USART_CR1_RE | USART_CR1_OVER8),
             (0x00000000U | 0x00000000U |
              (USART_CR1_TE | USART_CR1_RE) | 0x00000000U));
  MODIFY_REG(USART1->CR2, USART_CR2_STOP, 0);                  //设置停止位  1
  MODIFY_REG(USART1->CR3, USART_CR3_RTSE | USART_CR3_CTSE, 0); //HardwareFlowControl
#endif
  //设置波特率
  USART1->CR1 &= ~(1 << 15); //设置OVER8=0
  //USART1->CR1 |= (1 << 15);
  //usartdiv = (uint16_t)(USART_DIV_SAMPLING8(pclk2, 0, BaudRate));
  //brrtemp = usartdiv & 0xFFF0U;
  //brrtemp |= (uint16_t)((usartdiv & (uint16_t)0x000FU) >> 1U);
  //USART1->BRR = brrtemp;
  USART1->BRR = (uint16_t)(USART_DIV_SAMPLING16(pclk2, 0, BaudRate));
#if 1
  //输入时钟分频
  MODIFY_REG(USART1->PRESC, USART_PRESC_PRESCALER, 0);
  //USART_SetTXFIFOThreshold
  MODIFY_REG(USART1->CR3, USART_CR3_TXFTCFG, 0x00000000 << USART_CR3_TXFTCFG_Pos);
  //LL_USART_SetRXFIFOThreshold
  MODIFY_REG(USART1->CR3, USART_CR3_RXFTCFG, 0x00000000 << USART_CR3_RXFTCFG_Pos);
  CLEAR_BIT(USART1->CR1, USART_CR1_FIFOEN); //关闭fifo
  //ConfigAsyncMode
  CLEAR_BIT(USART1->CR2, (USART_CR2_LINEN | USART_CR2_CLKEN));
  CLEAR_BIT(USART1->CR3, (USART_CR3_SCEN | USART_CR3_IREN | USART_CR3_HDSEL));
  //使能接收非空中断
  SET_BIT(USART1->CR1, USART_CR1_RXNEIE_RXFNEIE);
  NVIC_SetPriority(USART1_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 3, 1));
  NVIC_EnableIRQ(USART1_IRQn);
  SET_BIT(USART1->CR1, USART_CR1_UE);

  //清除发送完成中断
  WRITE_REG(USART1->ICR, USART_ICR_TCCF);
  SET_BIT(USART1->CR1, USART_CR1_TCIE); //使能发送中断
#endif
  SET_BIT(USART1->CR1, USART_CR1_UE);
}

__STATIC_INLINE uint32_t USART_IsActiveFlag_RXNE(USART_TypeDef *USARTx)
{
  return ((READ_BIT(USARTx->ISR, USART_ISR_RXNE_RXFNE) == (USART_ISR_RXNE_RXFNE)) ? 1UL : 0UL);
}
__STATIC_INLINE uint32_t USART_IsActiveFlag_ORE(USART_TypeDef *USARTx)
{
  return ((READ_BIT(USARTx->ISR, USART_ISR_ORE) == (USART_ISR_ORE)) ? 1UL : 0UL);
}
__STATIC_INLINE void USART_ClearFlag_ORE(USART_TypeDef *USARTx)
{
  WRITE_REG(USARTx->ICR, USART_ICR_ORECF);
}
__STATIC_INLINE uint32_t USART_IsActiveFlag_TC(USART_TypeDef *USARTx)
{
  return ((READ_BIT(USARTx->ISR, USART_ISR_TC) == (USART_ISR_TC)) ? 1UL : 0UL);
}
__STATIC_INLINE void USART_ClearFlag_TC(USART_TypeDef *USARTx)
{
  WRITE_REG(USARTx->ICR, USART_ICR_TCCF);
}

#if 1
void USART1_IRQHandler(void)
{
  if ((USART_IsActiveFlag_RXNE(USART1) != RESET) ||
      USART_IsActiveFlag_ORE(USART1) == SET)
  {
    USART_ClearFlag_ORE(USART1);
    *(Usart1Buffer.RXData + Usart1Buffer.RXWriteCounter) = USART1->RDR; //把接收到的数据写入内存
    Usart1Buffer.RXWriteCounter++;
    if (Usart1Buffer.RXWriteCounter >= USART1_RX_BUFFER_MAX)
    {
      Usart1Buffer.RXWriteCounter = 0;
    }

    Usart1Buffer.RXFinishTime = USART_DELAYTIME; //置接收完成时间
    Usart1Buffer.RXFlag = USART_RXFLAG_BUSY;     //置接收标志
  }
  //发送完成中断
  if (USART_IsActiveFlag_TC(USART1) != RESET)
  {
    USART_ClearFlag_TC(USART1); //ICR的TC位置一消除中断
    //判断发送写入寄存器有没有异常
    if (Usart1Buffer.TXWriteCounter >= USART1_TX_BUFFER_MAX)
    {
      Usart1Buffer.TXWriteCounter = 0;
    }
    //发送没有完成
    if (Usart1Buffer.TXReadCounter != Usart1Buffer.TXWriteCounter)
    {
      //LL_USART_TransmitData8(USART1, *(Usart1Buffer.TXData + Usart1Buffer.TXReadCounter));
      USART1->TDR = *(Usart1Buffer.TXData + Usart1Buffer.TXReadCounter);
      Usart1Buffer.TXReadCounter++;
      if (Usart1Buffer.TXReadCounter >= USART1_TX_BUFFER_MAX)
      {
        Usart1Buffer.TXReadCounter = 0;
      }
    }
    //发送完成
    else
    {
      Usart1Buffer.TXFlag = USART_TXFLAG_IDLE;
#if USART1_RS485_ENABLE
      USART1_RECEIVE_ENABLE; //接收使能
#endif
    }
  }
}
#endif

//==============================================================
//功能:串口发送函数
//入口:发送数据的指针*SendData
//出口:数据的长度length
//==============================================================
u8 USART1_SendData(u8 *SendData, u8 length)
{
  u8 Counter = 0;

  //开始复制数据
  for (Counter = 0; Counter < length; Counter++)
  {
    Usart1Buffer.TXData[Usart1Buffer.TXWriteCounter] = *(SendData + Counter);
    Usart1Buffer.TXWriteCounter++;
    if (Usart1Buffer.TXWriteCounter >= USART1_TX_BUFFER_MAX)
    {
      Usart1Buffer.TXWriteCounter = 0;
    }
  }

#if USART1_RS485_ENABLE
  USART1_SEND_ENABLE; //RS485发送使能
#endif

  //假如已经启动发送程序，直接返回
  if (Usart1Buffer.TXFlag == USART_TXFLAG_BUSY)
    return Counter;
  //假如没有启动发送程序，发送启动程序
  //LL_USART_TransmitData8(USART1, *(Usart1Buffer.TXData + Usart1Buffer.TXReadCounter));
  USART1->TDR = *(Usart1Buffer.TXData + Usart1Buffer.TXReadCounter);
  Usart1Buffer.TXReadCounter++;
  if (Usart1Buffer.TXReadCounter >= USART1_TX_BUFFER_MAX)
  {
    Usart1Buffer.TXReadCounter = 0;
  }
  Usart1Buffer.TXFlag = USART_TXFLAG_BUSY;
  return Counter;
}

//==============================================================
//功能:串口接收函数
//入口:保存数据的指针*RecevieData
//出口:数据的长度
//==============================================================
u8 USART1_ReceiveData(u8 *ReceiveData)
{
  u8 Counter = 0;

  if (Usart1Buffer.RXFlag != USART_RXFLAG_FINISH)
    return Counter; //接收未完成，返回

  //判断接收写入寄存器有没有异常
  if (Usart1Buffer.RXWriteCounter >= USART1_RX_BUFFER_MAX)
  {
    Usart1Buffer.RXWriteCounter = 0;
  }
  //数据完整读出
  while (Usart1Buffer.RXWriteCounter != Usart1Buffer.RXReadCounter)
  {
    *(ReceiveData + Counter) = Usart1Buffer.RXData[Usart1Buffer.RXReadCounter];
    Usart1Buffer.RXReadCounter++;
    if (Usart1Buffer.RXReadCounter >= USART1_RX_BUFFER_MAX)
    {
      Usart1Buffer.RXReadCounter = 0;
    }
    Counter++;
  }
  Usart1Buffer.RXFlag = USART_RXFLAG_IDLE; //处理完成，重置接收标志
  return Counter;
}

//该程序需要放置在系统时钟程序中
void USART1_TimeOutCounter(void)
{
  if (Usart1Buffer.RXFlag == USART_RXFLAG_BUSY)
  {
    if (Usart1Buffer.RXFinishTime)
    {
      Usart1Buffer.RXFinishTime--;
    }
    else
    {
      Usart1Buffer.RXFlag = USART_RXFLAG_FINISH;
    }
  }
  if (Usart1Buffer.TXFinishTime)
  {
    Usart1Buffer.TXFinishTime--;
  }
}
